/*
 * Copyright (C) 2010-2011 sunjumper@163.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package mfinder.impl;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import mfinder.ActionFactory;
import mfinder.ActionInvocation;
import mfinder.MFinderException;
import mfinder.annotation.Action;
import mfinder.annotation.Interceptor;
import mfinder.annotation.InterceptorStack;
import mfinder.annotation.Namespace;
import mfinder.annotation.Result;
import mfinder.annotation.ResultType;
import mfinder.impl.DefaultActionInvocation.ResultProxy;
import mfinder.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 默认ActionFactory的实现类，以‘/’作为路径的分隔符。
 * DefaultActionFactory中的加载和调用的拦截器、结果类型对象均为单例；
 * {@link Action}对象根据其{@link Action#scope()}属性判断是否单例。
 * DefaultActionFactory中的Action、拦截器、拦截栈及结果类型的集合在初始化时加载完成，
 * 之后任何情况下DefaultActionFactory不再执行集合的修改和删除操作。对返回集合进行的修改和删除请自行保证其线程安全性。
 */
public class DefaultActionFactory implements ActionFactory {

    /** 日志 */
    private static final Logger LOG = LoggerFactory.getLogger(DefaultActionFactory.class);

    /**
     * The extension separator character.
     */
    public static final char EXTENSION_SEPARATOR = '.';

    /** 路径分隔符 */
    public static final char PATH_SEPARATOR = '/';

    /** 全匹配标识 */
    private String match = PathTree.SINGLE_MATCH;

    /** 路径后缀，带'.' */
    private String extension = null;

    /** Action运行时上下文的类型，用于传递上下文参数时的界限判断 */
    private Class<? extends ActionInvocation> actionInvocationClass;

    /**
     * 默认拦截栈名称。
     * 默认拦截栈名称的设置仅在初始化Action时，更改默认拦截栈名称仅影响以后加载的Action。
     *
     * @see #createActionProxy(Method, Object)
     */
    private String defaultInterceptorStack = null;

    /**
     * 默认视图类型。
     * 默认视图类型的更改影响每次调用。
     *
     * @see #invokeAction(String, Object[])
     */
    private String defaultResultType = null;

    /** {@link #actionsCache}最大缓存数目，默认最大缓存50w条记录 */
    private int actionCacheNumber = 500000;
////////////////////////////////////////////////////////////////////////////////

    /** 拦截器 */
    private final Map<String, InterceptorProxy> interceptors = new HashMap<String, InterceptorProxy>();

    /** 拦截栈 */
    private final Map<String, InterceptorStackProxy> interceptorStacks = new HashMap<String, InterceptorStackProxy>();

    /** 实际的Action树结构路径映射 */
    private final PathTreeMap<ActionProxy> actions = new PathTreeMap<ActionProxy>(PATH_SEPARATOR);

    /** Action路径与代理对象的映射缓存 */
    private final Map<String, ActionCacheEntry> actionsCache = new java.util.concurrent.ConcurrentHashMap<String, ActionCacheEntry>(10000);

    /** 结果类型 */
    private final Map<String, ResultTypeProxy> resultTypes = new HashMap<String, ResultTypeProxy>();

    /**
     * 通过路径调用相应的Action，可以传递Action代理方法相应的参数。
     * Action调用是否为线程安全取决于路径所映射方法的线程安全性。
     *
     * @param path Action的映射路径。
     * @param params Action的调用参数。
     *
     * @return 调用后的结果；如果结果为字符串类型非空且存在结果对象，则查找相应的结果类型并返回调用后的结果；
     * 反之直接返回结果。
     *
     * @throws MFinderException 如果发生调用错误。
     */
    @Override
    public Object invokeAction(String path, Object... params) throws MFinderException {

        //remove the extension
        int index = path.lastIndexOf(EXTENSION_SEPARATOR);
        if (index != -1) {
            path = path.substring(0, index);
        }

        //create ActionInvocation
        ActionInvocation invocation = createActionInvocation(path, params);

        //invoke
        Object res = null;
        try {
            res = invocation.invoke(params);
            //result is string
            if (res instanceof String) {
                ActionProxy ap = invocation.getActionProxy();
                Result result = ap.getResults().get(res.toString());
                //如果存在相应的字符结果映射
                if (result != null) {
                    String type = result.type();
                    //default result type
                    if (StringUtil.isNull(type))
                        type = defaultResultType;

                    ResultTypeProxy rtp = resultTypes.get(type);
                    if (rtp == null)
                        throw new MFinderException("no such ResultType [" + type + "] at : " + ap.getMethodInfo(), ap);

                    if (rtp.isRequireAction()) {
                        ((DefaultActionInvocation) invocation).setResult(result);
                    }
                    //结果类型调用
                    Object rr = rtp.invoke(rtp.isRequireAction() ? invocation : null);
                    if (rr != null)
                        res = rr;
                } else {
                    //调用非完全匹配路径的结果对象
                    Object rr = invokeResult(invocation, res);
                    if (rr != null)
                        res = rr;
                }
            } else {
                //非字符串结果的对象处理方式
                Object rr = invokeObjectResult(invocation, res);
                if (rr != null)
                    res = rr;
            }
        } catch (InvocationProxyException e) {
            //去除不必要的InvocationProxyException异常，封装异常的源并抛出。
            throw new InvocationProxyException(e.getSource(), null);
        }
        return res;
    }

    /**
     * 创建Action调用时的上下文对象。
     *
     * @param path Action的映射路径。
     * @param params Action的调用参数。
     *
     * @return Action调用时的上下文对象。
     */
    protected ActionInvocation createActionInvocation(String path, Object... params) {

        //cache
        ActionCacheEntry ace = actionsCache.get(path);
        //是否在缓存中
        boolean inCache = ace != null;

        //Action代理对象
        ActionProxy ap = null;
        //路径的参数匹配映射
        Map<String, String> matchParameters = null;

        //get from cache
        if (inCache) {
            ap = ace.actionProxy;
            matchParameters = ace.matchParameters;
        } else {
            //initiate matchParameters
            matchParameters = new HashMap<String, String>(5);
            ap = actions.get(path, matchParameters);
            //set matchParameters null if empty
            if (matchParameters.isEmpty())
                matchParameters = null;

            if (ap == null)
                throw new MFinderException("no such Action : " + path, null);

            //put in cache
            ace = new ActionCacheEntry(ap, matchParameters);
            putActionCache(path, ace);
        }

        //scope action
        ap = ap.getInstance();
        //create DefaultActionInvocation
        return new DefaultActionInvocation(this, ap, matchParameters, params);
    }

    /**
     * 用于子类继承，提供非完全匹配路径的结果对象的调用方式。
     * 默认提供全字符串结果的匹配处理。
     *
     * @param invocation Action运行时上下文。
     * @param res Action调用完成后的结果。
     *
     * @return 调用相应结果类型后的值，无匹配则返回 null。
     */
    protected Object invokeResult(ActionInvocation invocation, Object res) {
        ActionProxy ap = invocation.getActionProxy();
        Result result = ap.getResults().get(match);
        if (result != null) {
            //返回的结类型及路径信息
            String pathinfo = res.toString();
            String type = StringUtil.isNull(result.type()) ? defaultResultType : result.type();
            String loc = result.location();
            //首個非空格非分隔符的位置
            int begin = -1;
            //分隔符前的最后一个非空格字符的位置
            int p1 = -1;
            //分隔符的位置
            int colon = -1;
            int len = pathinfo.length();
            //定位分隔符位置
            for (int i = 0; i < len; i++) {
                char c = pathinfo.charAt(i);
                //may extend
                if (c == ':' || c == '：') {
                    colon = i;
                    break;
                } else {
                    if (c != ' ') {
                        p1 = i;
                        if (begin == -1)
                            begin = i;
                    }
                }
            }
            //判断结果类型
            switch (colon) {
                case -1:
                    begin = 0;
                    p1 = len - 1;
                    while (begin < p1 && pathinfo.charAt(begin) == ' ')
                        begin++;
                    while (begin < p1 && pathinfo.charAt(p1) == ' ')
                        p1--;
                    //非空
                    if (begin < p1)
                        type = pathinfo.substring(begin, p1 + 1);
                    break;
                case 0:
                    break;
                default:
                    //非空
                    if (begin != -1)
                        type = pathinfo.substring(begin, p1 + 1);
            }
            //分隔符非末位，判断结果路径
            if (colon != -1 && colon != len - 1) {
                //分隔符后的第一个非空格字符的位置
                int p2 = colon + 1;
                //最后一个非空字符的位置
                int end = len - 1;
                while (p2 < end && pathinfo.charAt(p2) == ' ')
                    p2++;
                while (p2 < end && pathinfo.charAt(end) == ' ')
                    end--;

                if (p2 != end)
                    loc = pathinfo.substring(p2, end + 1);
            }
            ResultTypeProxy rtp = resultTypes.get(type);
            if (rtp == null)
                throw new MFinderException("no such ResultType [" + type + "] at : " + ap.getMethodInfo(), ap);

            if (rtp.isRequireAction())
                ((DefaultActionInvocation) invocation).setResult(new ResultProxy(match, type, loc));
            //结果类型调用
            return rtp.invoke(rtp.isRequireAction() ? invocation : null);
        }
        return null;
    }

    /**
     * 用于子类继承，提供非字符串对象的处理方式。
     * 默认直接返回非字符串对象。
     *
     * @param invocation Action运行时上下文。
     * @param res Action调用完成后的结果。
     *
     * @return 调用相应结果类型后的值。
     */
    protected Object invokeObjectResult(ActionInvocation invocation, Object res) {
        return res;
    }

    /**
     * 添加Action的路径及代理对象至缓存。
     *
     * @param path Action的路径。
     * @param ace Action的缓存对象。
     */
    protected void putActionCache(String path, ActionCacheEntry ace) {
        //如果缓存数据大于50w条，则清空缓存
        if (actionsCache.size() > actionCacheNumber)
            actionsCache.clear();
        actionsCache.put(path, ace);
    }

    /**
     * 清除Action的路径映射缓存。
     */
    public void clearActionCache() {
        actionsCache.clear();
    }

    @Override
    public void clear() {
        actionsCache.clear();
        actions.clear();
        interceptorStacks.clear();
        interceptors.clear();
        resultTypes.clear();
    }
////////////////////////////////////////////////////////////////////////////////

    /**
     * 添加拦截器。
     *
     * @param ip 拦截器代理对象。
     */
    public void addInterceptor(InterceptorProxy ip) {
        String name = ip.getName();

        if (StringUtil.isNull(name))
            throw new IllegalArgumentException("null name in Interceptor : " + ip.getMethodInfo());

        if (interceptors.containsKey(name)) {
            LOG.warn("duplicate Interceptor [" + name + "] : "
                    + interceptors.get(name).getMethodInfo() + " to "
                    + ip.getMethodInfo());
        } else {
            LOG.info("add Interceptor : " + name + " - " + ip.getMethodInfo());
        }
        interceptors.put(name, ip);
    }

    /**
     * 添加拦截器。
     *
     * @param obj 包含{@link Interceptor}注解的类或实例对象。
     *
     * @see mfinder.annotation.Interceptor
     */
    @Override
    public void addInterceptors(Object obj) {
        boolean isCls = obj instanceof Class;
        Class cls = isCls ? (Class) obj : obj.getClass();
        Object invoker = isCls ? null : obj;
        Method[] ms = cls.getDeclaredMethods();
        for (Method m : ms) {
            int mod = m.getModifiers();
            //带@Interceptor的public/protected方法
            if ((Modifier.isPublic(mod) || Modifier.isProtected(mod))
                    && m.isAnnotationPresent(Interceptor.class)) {
                m.setAccessible(true);
                //static method
                if (Modifier.isStatic(mod)) {
                    addInterceptor(createInterceptorProxy(m, null));
                } else {
                    //为类对象且调用者为 null
                    if (isCls && invoker == null)
                        try {
                            invoker = cls.newInstance();
                        } catch (IllegalAccessException e) {
                            throw new MFinderException(e, null);
                        } catch (InstantiationException e) {
                            throw new MFinderException(e, null);
                        }
                    //the same object
                    addInterceptor(createInterceptorProxy(m, invoker));
                }
            }
        }
    }

    /**
     * 添加拦截栈。
     *
     * @param isp 拦截栈代理对象。
     */
    public void addInterceptorStack(InterceptorStackProxy isp) {
        String name = isp.getName();
        if (interceptorStacks.containsKey(name)) {
            LOG.error("duplicate InterceptorStack : " + name);
        } else {
            LOG.info("add InterceptorStack : " + name + " - " + isp);
        }
        interceptorStacks.put(name, isp);
    }

    /**
     * 添加拦截栈。
     *
     * @param obj 包含{@link InterceptorStack}注解的类或实例对象。
     *
     * @see mfinder.annotation.InterceptorStack
     */
    @Override
    public void addInterceptorStacks(Object obj) {
        boolean isCls = obj instanceof Class;
        Class cls = isCls ? (Class) obj : obj.getClass();
        Object invoker = isCls ? null : obj;
        Field[] fs = cls.getDeclaredFields();
        for (Field f : fs) {
            int mod = f.getModifiers();
            //带@InterceptorStack的public属性
            if (Modifier.isPublic(mod) && f.isAnnotationPresent(InterceptorStack.class)) {
                f.setAccessible(true);
                try {
                    //static field
                    if (Modifier.isStatic(mod)) {
                        addInterceptorStack(createInterceptorStackProxy(f, null));
                    } else {
                        //为类对象且调用者为 null
                        if (isCls && invoker == null)
                            invoker = cls.newInstance();
                        //the same object
                        addInterceptorStack(createInterceptorStackProxy(f, invoker));
                    }
                } catch (IllegalAccessException e) {
                    throw new MFinderException(e, null);
                } catch (InstantiationException e) {
                    throw new MFinderException(e, null);
                }
            }
        }
    }

////////////////////////////////////////////////////////////////////////////////
    /**
     * 添加结果类型。
     *
     * @param rtp 结果类型的代理对象。
     */
    public void addResultType(ResultTypeProxy rtp) {
        String type = rtp.getType();

        if (StringUtil.isNull(type))
            throw new IllegalArgumentException("null type in ResultType : " + rtp.getMethodInfo());

        if (resultTypes.containsKey(type)) {
            LOG.warn("duplicate Result [" + type + "] : "
                    + resultTypes.get(type).getMethodInfo() + " to "
                    + rtp.getMethodInfo());
        } else {
            LOG.info("add Result : " + type + " - " + rtp.getMethodInfo());
        }
        resultTypes.put(type, rtp);
    }

    /**
     * 添加结果类型。
     *
     * @param obj 包含{@link ResultType}注解的类或实例对象。
     *
     * @see mfinder.annotation.ResultType
     */
    @Override
    public void addResultTypes(Object obj) {
        boolean isCls = obj instanceof Class;
        Class cls = isCls ? (Class) obj : obj.getClass();
        Object invoker = isCls ? null : obj;
        Method[] ms = cls.getDeclaredMethods();
        for (Method m : ms) {
            int mod = m.getModifiers();
            //带@ResultType的public/protected方法
            if ((Modifier.isPublic(mod) || Modifier.isProtected(mod))
                    && m.isAnnotationPresent(ResultType.class)) {
                m.setAccessible(true);
                //static method
                if (Modifier.isStatic(mod)) {
                    addResultType(createResultTypeProxy(m, null));
                } else {
                    //为类对象且调用者为 null
                    if (isCls && invoker == null)
                        try {
                            invoker = cls.newInstance();
                        } catch (IllegalAccessException e) {
                            throw new MFinderException(e, null);
                        } catch (InstantiationException e) {
                            throw new MFinderException(e, null);
                        }
                    //the same object
                    addResultType(createResultTypeProxy(m, invoker));
                }
            }
        }
    }

////////////////////////////////////////////////////////////////////////////////
    /**
     * 添加Action。
     *
     * @param ap Action代理对象。
     */
    public void addAction(ActionProxy ap) {
        String aPath = ap.getPath();

        if (StringUtil.isNull(aPath))
            throw new IllegalArgumentException("null path in Action : " + ap.getMethodInfo());

        ActionProxy exist = actions.get(aPath);
        if (exist != null) {
            LOG.warn("duplicate Action [" + aPath + "] : "
                    + exist.getMethodInfo() + " to "
                    + ap.getMethodInfo());
        } else {
            LOG.info("add Action : " + aPath + " - " + ap.getMethodInfo());
        }
        actions.put(aPath, ap);
    }

    /**
     * 添加Action。
     *
     * @param obj 包含{@link Action}注解的类或实例对象。
     *
     * @see mfinder.annotation.Action
     */
    @Override
    public void addActions(Object obj) {
        //判断传入参数为类或实例对象
        boolean isCls = obj instanceof Class;
        Class cls = isCls ? (Class) obj : obj.getClass();
        Object invoker = isCls ? null : obj;
        Method[] ms = cls.getDeclaredMethods();
        for (Method m : ms) {
            int mod = m.getModifiers();
            //带@Action的public/protected方法
            if ((Modifier.isPublic(mod) || Modifier.isProtected(mod))
                    && m.isAnnotationPresent(Action.class)) {
                m.setAccessible(true);
                //static method
                if (Modifier.isStatic(mod)) {
                    addAction(createActionProxy(m, null));
                } else {
                    if (isCls && invoker == null)
                        try {
                            invoker = cls.newInstance();
                        } catch (IllegalAccessException e) {
                            throw new MFinderException(e, null);
                        } catch (InstantiationException e) {
                            throw new MFinderException(e, null);
                        }
                    //the same object
                    addAction(createActionProxy(m, invoker));
                }
            }
        }
    }

////////////////////////////////////////////////////////////////////////////////
    /**
     * 创建Interceptor代理对象。
     *
     * @param method 指定的方法。
     * @param obj 方法所在的对象。
     *
     * @return Interceptor代理对象。
     */
    private InterceptorProxy createInterceptorProxy(Method method, Object obj) {
        Interceptor interceptor = method.getAnnotation(Interceptor.class);
        Class[] params = method.getParameterTypes();

        //check interceptor invoke args
        boolean bool = false;
        //interceptor代理的方法无参数或参数仅为ActionInvocation或其子类
        if (params.length == 0) {
            bool = false;
        } //未指定actionInvocationClass参数类型时允许ActionInvocation任意子类；否则为actionInvocationClass的父类
        else if (params.length == 1
                && actionInvocationClass == null
                ? ActionInvocation.class.isAssignableFrom(params[0])
                : params[0].isAssignableFrom(actionInvocationClass)) {
            bool = true;
        } else {
            throw new IllegalArgumentException("illegal arguments in Interceptor : " + method);
        }
        InterceptorProxy ip = new InterceptorProxy(interceptor.name().trim(), method, obj, bool);
        return ip;
    }

    /**
     * 创建InterceptorStack代理对象
     *
     * @param field 指定的字段。
     * @param obj 字段所在对象。
     *
     * @return InterceptorStack代理对象。
     *
     * @throws IllegalAccessException 如果调用的对象无法访问指定字段。
     */
    private InterceptorStackProxy createInterceptorStackProxy(Field field, Object obj) throws
            IllegalAccessException {
        InterceptorStack interceptorStack = field.getAnnotation(InterceptorStack.class);
        String name = interceptorStack.name().trim();

        //interceptorStack name
        //未指定拦截栈名称则取字符串的值为名称
        if (StringUtil.isNull(name)) {
            name = field.get(obj).toString();
            //空命名异常
            if (StringUtil.isNull(name))
                throw new IllegalArgumentException("null name in InterceptorStack : "
                        + field.getName() + " at " + obj.getClass());
        }
        //interceptors name
        String[] names = interceptorStack.interceptors();

        List<InterceptorProxy> list = null;
        if (names != null && names.length != 0) {
            list = new ArrayList<InterceptorProxy>(names.length);
            //add interceptorStack
            //for (int i = names.length - 1; i >= 0; i--) {
            for (int i = 0; i < names.length; i++) {
                InterceptorProxy ip = interceptors.get(names[i]);
                //if null
                if (ip == null) {
                    LOG.warn("no such Interceptor : " + names[i]);
                } else {
                    list.add(ip);
                }
            }
        }
        return new InterceptorStackProxy(name, field, list);
    }

    /**
     * 创建ResultType代理对象。
     *
     * @param method 指定的方法。
     * @param obj 方法所在的对象。
     *
     * @return ResultType代理对象。
     */
    private ResultTypeProxy createResultTypeProxy(Method method, Object obj) {
        ResultType type = method.getAnnotation(ResultType.class);
        Class[] params = method.getParameterTypes();

        boolean bool = false;
        //ResultType代理的方法无参数或参数仅为ActionInvocation或其子类
        if (params.length == 0) {
            bool = false;
        } else if (params.length == 1
                && actionInvocationClass == null
                ? ActionInvocation.class.isAssignableFrom(params[0])
                : params[0].isAssignableFrom(actionInvocationClass)) {
            bool = true;
        } else {
            throw new IllegalArgumentException("illegal arguments in ResultType : " + method);
        }

        ResultTypeProxy rp = new ResultTypeProxy(type.type().trim(), method, obj, bool);
        return rp;
    }

    /**
     * 创建Action代理对象。
     *
     * @param method 指定的方法。
     * @param obj 方法所在的对象。
     *
     * @return Action代理对象。
     */
    private ActionProxy createActionProxy(Method method, Object obj) {
        Namespace ns = method.getDeclaringClass().getAnnotation(Namespace.class);
        //trim empay and '/'
        String namespace = ns == null ? PATH_SEPARATOR + "" : PATH_SEPARATOR + StringUtil.trim(ns.name(), PATH_SEPARATOR);

        String path = null;
        //not nullable Action
        Action action = method.getAnnotation(Action.class);
        //Action名称可能为空字符串
        String aname = action.name().trim();
        if ("".equals(aname)) {
            //Action名称为空字符串时取其方法的名称（区分大小写）
            aname = method.getName();
            //if namespace is '/' or not
            path = namespace.length() == 1 ? PATH_SEPARATOR + aname : namespace + PATH_SEPARATOR + aname;
        } else {
            //action's name can't be null by annotation
            String name = StringUtil.trim(aname, PATH_SEPARATOR);
            //if action's name is trim as empty
            if (name.isEmpty()) {
                path = namespace;
            } else if (PATH_SEPARATOR == aname.charAt(0)) {
                path = PATH_SEPARATOR + name;
            } else {
                //if namespace is '/' or not
                path = namespace.length() == 1 ? PATH_SEPARATOR + name : namespace + PATH_SEPARATOR + name;
            }
        }

        //Action中不记录路径的后缀名称
        ActionProxy ap = new ActionProxy(namespace, path, action, method, obj);

        //interceptorStack
        String stackName = action.interceptorStack().trim();
        boolean hasStackName = !StringUtil.isNull(stackName);
        //1st stackname check
        if (!hasStackName) {
            //namespace defaultInterceptorStack
            if (ns != null)
                stackName = ns.interceptorStack();
            //defaultInterceptorStack
            if (StringUtil.isNull(stackName))
                stackName = defaultInterceptorStack;

            hasStackName = !StringUtil.isNull(stackName);
        }

        //2nd stackname check
        if (hasStackName) {
            InterceptorStackProxy isp = interceptorStacks.get(stackName);
            if (isp == null) {
                LOG.warn("no such InterceptorStack [" + stackName + "] defined in : " + ap.getMethodInfo());
                //ap.setInterceptors(Collections.EMPTY_LIST);
            } else {
                ap.setInterceptors(isp.getInterceptors());
            }
        }

        //set results
        Result[] rs = action.results();
        Map<String, Result> res = new HashMap<String, Result>(rs.length);
        for (Result r : rs) {
            res.put(r.name(), r);
        }
        ap.setResults(res);

        return ap;
    }

    /**
     * 为路径添加后缀名。
     *
     * @param path 全路径名称。
     *
     * @return 处理后的带后缀的全路径名称。
     */
    public String addExtension(String path) {
        //add extension
        if (!path.equals(PATH_SEPARATOR + "") && !StringUtil.isNull(extension) && !path.endsWith(extension)) {
            path += extension;
        }
        return path;
    }

////////////////////////////////////////////////////////////////////////////////
    @Override
    public Map<String, ActionProxy> getActions() {
        return actions;
    }

    /**
     * 返回缓存的Action路径与其代理对象的映射。
     *
     * @return 缓存的Action路径与其代理对象的映射。
     */
    public Map<String, ActionCacheEntry> getActionsCache() {
        return actionsCache;
    }

    @Override
    public Map<String, InterceptorProxy> getInterceptors() {
        return interceptors;
    }

    @Override
    public Map<String, InterceptorStackProxy> getInterceptorStacks() {
        return interceptorStacks;
    }

    @Override
    public Map<String, ResultTypeProxy> getResultTypes() {
        return resultTypes;
    }

    @Override
    public String getDefaultInterceptorStack() {
        return defaultInterceptorStack;
    }

    /**
     * 设置默认拦截栈名称。
     * 更改默认拦截栈名称对已存在的拦截栈{@link #interceptorStacks}无影响。
     * 更改默认拦截栈名称对已存在的{@link #actions}无影响。
     *
     * @param defaultInterceptorStack 默认拦截栈名称。
     */
    @Override
    public void setDefaultInterceptorStack(String defaultInterceptorStack) {
        LOG.info("setDefaultInterceptorStack : " + defaultInterceptorStack);
        this.defaultInterceptorStack = defaultInterceptorStack;
    }

    @Override
    public String getDefaultResultType() {
        return defaultResultType;
    }

    /**
     * 设置默认结果视图类型。
     * 更改默认结果视图类型会影响已存在的{@link #actions}的结果调用。
     * 如果已有的Action调用结束后使用了默认视图类型，则会被影响。
     *
     * @param defaultResultType 默认视图类型。
     */
    @Override
    public void setDefaultResultType(String defaultResultType) {
        LOG.info("setDefaultResultType : " + defaultResultType);
        this.defaultResultType = defaultResultType;
    }

    /**
     * 返回路径后缀名称。
     *
     * @return 路径后缀名称。
     */
    public String getExtension() {
        return extension;
    }

    /**
     * 设置路径后缀名称，默认为设置值添加‘.’后缀。
     * 更改路径后缀名称对已存在的{@link #actions}无影响。
     *
     * @param extension 路径后缀名称。
     */
    public void setExtension(String extension) {
        if (extension == null)
            return;
        String ext = extension.trim();
        if ("".equals(ext))
            return;
        this.extension = EXTENSION_SEPARATOR == extension.charAt(0) ? ext : EXTENSION_SEPARATOR + ext;
        LOG.info("setExtension : " + this.extension);
    }

    /**
     * Action运行时上下文的类型。
     *
     * @return Action运行时上下文的类型。
     */
    public Class<? extends ActionInvocation> getActionInvocationClass() {
        return actionInvocationClass;
    }

    /**
     * 设置Action运行时上下文的类型。
     *
     * @param actionInvocationClass Action运行时上下文的类型。
     */
    public void setActionInvocationClass(Class<? extends ActionInvocation> actionInvocationClass) {
        this.actionInvocationClass = actionInvocationClass;
        LOG.info("setActionInvocationClass : " + this.actionInvocationClass);
    }

    /**
     * 返回{@link #getActionsCache()}的最大缓存数目。
     *
     * @return {@link #getActionsCache()}的最大缓存数目。
     */
    public int getActionCacheNumber() {
        return actionCacheNumber;
    }

    /**
     * 设置{@link #getActionsCache()}的最大缓存数目。
     *
     * @param actionCacheNumber {@link #getActionsCache()}的最大缓存数目。
     */
    public void setActionCacheNumber(int actionCacheNumber) {
        this.actionCacheNumber = actionCacheNumber;
        LOG.info("setActionCacheNumber : " + this.actionCacheNumber);
    }

    /**
     * 缓存对象。
     */
    public static class ActionCacheEntry {

        /** Action的代理对象 */
        ActionProxy actionProxy;

        /** Actino路径的参数匹配映射，如果没有则为 null */
        Map<String, String> matchParameters;

        /**
         * 构造一个无属性的缓存对象。
         */
        public ActionCacheEntry() {
        }

        /**
         * 构造一个指定Action的代理对象和Actino路径的参数匹配映射的缓存对象。
         *
         * @param actionProxy Action的代理对象。
         * @param matchParameters Actino路径的参数匹配映射。
         */
        public ActionCacheEntry(ActionProxy actionProxy,
                Map<String, String> matchParameters) {
            this.actionProxy = actionProxy;
            this.matchParameters = matchParameters;
        }
    }
}
